# -*- coding: utf-8 -*-
import datetime
from pyshare.utils.time_utils import getCT
from pyshare.bll.errors import ChargingError

class ChargingBase(object):
    """ 冷却基类 """

    __slots__ = ()

    capacity = NotImplemented
    base_time = NotImplemented
    cooldown_period = NotImplemented


    @property
    def used(self):
        """已使用的次数。

        :rtype: int
        """
        return self.capacity - self.remaining

    def isfull(self):
        """可用次数是否已满。

        :rtype: bool
        """
        return self.remaining >= self.capacity

    def isempty(self):
        """可用次数是否为 0 。

        :rtype: bool
        """
        return self.remaining == 0

    def ischarging(self):
        """是否正在补充。

        :rtype: bool
        """
        return not self.isfull()

    def refill(self):
        """补充全部次数。"""
        self.remaining = self.capacity

    def charged_period(self):
        """当前补充已进行的时间。

        :rtype: datetime.timedelta
        """
        if not self.ischarging():
            raise ChargingError('not charging')

        a = (getCT() - self.base_time).total_seconds()
        b = self.cooldown_period.total_seconds()
        t = datetime.timedelta(seconds=(a % b))
        return t

    def charge_at(self):
        """当前补充完成的时刻。

        :rtype: datetime.datetime
        """
        return datetime.datetime.now() + self.waiting_period()

    def waiting_period(self):
        """距当前补充完成仍需等待的时间。

        :rtype: datetime.timedelta
        """
        if not self.ischarging():
            raise ChargingError('not charging')

        return self.cooldown_period - self.charged_period()

    def asdict(self):
        d = {
            'Remaining': self.remaining,
            'MaxRounds': self.capacity,
        }

        if self.ischarging():
            d['ChargeAt'] = self.charge_at()

        return d


class ChargingMixin(ChargingBase):
    """
    冷却时间固定的倒计时方法类，使用base_time记录
    """

    @property
    def remaining(self):
        """剩余可用次数。

        例: cd = 10s, x = now() - base_time = 13s

        00   10   20
        ---------------
               ^13

        则当前剩余次数为 1 ，已等待冷却时间为 3s 。
        此时使用后 x = 3，剩余次数为 0 ，已等待冷却时间仍未 3s 。
        然后进行一次加速，则 x = 10，剩余次数为 1 ，已等待冷却时间为 0 s。

        :rtype: int
        """
        a = (getCT() - self.base_time).total_seconds()
        b = self.cooldown_period.total_seconds()
        r = int(a // b)
        return min(self.capacity, r)

    @remaining.setter
    def remaining(self, value):
        """修改剩余可用次数。"""
        if value < 0 or value > self.capacity:
            raise ChargingError('out of capacity')

        x = getCT() - self.cooldown_period * value
        # 次数增加时重置冷却
        if self.ischarging() and value <= self.remaining:
            self.base_time = x - self.charged_period()
        else:
            self.base_time = x



class ChargingNoLimitMixin(ChargingBase):
    """
    无上限，冷却时间固定
    使用base_time记录开始倒计时时间
    """

    # 记录值
    record = NotImplemented

    @property
    def remaining(self):
        """剩余可用次数。
        :rtype: int
        """
        # 若超出上限则直接返回
        if self.record <= self.capacity:
            a = (getCT() - self.base_time).total_seconds()
            b = self.cooldown_period.total_seconds()
            c = int(a // b)

            r = self.record + c
            self.base_time += self.cooldown_period * c

            self.record = min(self.capacity, r)
        return self.record

    @remaining.setter
    def remaining(self, value):
        """修改剩余可用次数。"""
        # 若为第一次使用或道具恢复则更新倒计时时间
        if self.isfull():
            self.base_time = getCT()

        if value < 0:
            raise ChargingError('out of capacity')
        else:
            self.record = value

